#!/usr/bin/perl -w
use warnings;
use strict;
use Getopt::Long qw(:config gnu_getopt);
use Storable qw( retrieve );
BEGIN {
    use File::Basename;
    my $path = dirname($0);
    $path = '.' unless defined $path && $path ne '';
    #print STDERR "pushing INC path: [$path]\n";
    push @INC, $path;
}
use FieldHash;
my %options = (
    FS => "\t",
);
my @options_specs = (
    'input|i=s',
    'output|o=s',
    'repository|r=s',
    'help|h|?',
    'FS|t=s',
);
error(-1, "Please run the program with option '--help'.")
    unless GetOptions(\%options, @options_specs);
usage() if $options{help};
$options{input} = $ARGV[0] if (!defined($options{input}) && @ARGV == 1);
error(-1, "You must specify input file.") unless defined($options{input});
error(-1, "You must specify repository file.") unless defined($options{repository});
my $FS = $options{FS};
my $wafer_data = retrieve($options{input}) or error(-1, "cannot retrieve: $options{input}: $!");
my $yield_repo = do $options{repository} or error(-1, "cannot 'do' repository: $options{repository}: $!");
if (defined($options{output})) {
    if ($options{output} eq '.') {
        # default option
        ($options{output} = $options{input}) =~ s/\.\w+$/.yield.csv/;
    }
    open OUTPUT, '>', $options{output} or error(3, "cannot open output: $options{output}: $!");
    select OUTPUT;
}

# =====================================================================

out('Product', $wafer_data->{Test_Program_Name});
out('Wafer ID', $wafer_data->{Lot_Number});
print "\n";

for my $i (0 .. $#$yield_repo) {
    yield($wafer_data, $yield_repo->[$i]);
}

# =====================================================================

close OUTPUT if defined($options{output});

exit 0;

# =====================================================================

sub yield {
    my ($data, $specs) = @_;
    my $limits = $specs->{limits};
    my @desc = map $_->[1], @$limits;
    my @fails = map 0, @desc;
    tie my %ic, 'FieldHash', Name => $data->{Dies_Data}[0];
    my $pass = 0;
    for my $i (1 .. $#{$data->{Dies_Data}}) {
        (tied %ic)->data($data->{Dies_Data}[$i]);
        my $fail = 0;
        for my $j (0 .. $#$limits) {
            my $limit = $limits->[$j];
            my $code = $limit->[0];
            unless ( $code->(\%ic) ) {
                $fails[$j] += 1;
                $fail++;
            }
        }
        if ($fail == 0) {
            $pass++;
        }
    }
    out('Specs', $specs->{name});
    out('Yield', $pass, sprintf("%.2lf%%", $pass * 100 / $data->{Gross_Dies}));
    out('Limit', 'Fail count', 'Fail rate');
    for my $i (0 .. $#fails) {
        out($desc[$i], $fails[$i], sprintf("%.2lf%%", $fails[$i] * 100 / $data->{Gross_Dies}) );
    }
    print "\n";
    return 1;
}

sub out {
    print join($FS, @_), "\n";
}

sub usage {
    (my $PROG = $0) =~ s/.*[\\\/]//;
    print STDERR <<"EO_USAGE";
usage:
    $PROG [ OPTIONS ] -i INPUT -o OUTPUT
options:
    -i, --input=FILE   specify input file
    -o, --output=FILE  specify output file
    -h, --help         print this help screen
EO_USAGE
    exit 0 unless defined($_[0]);
    1;
}

sub error {
    my $exit_status = shift;
    my ($package, $filename, $line, $subroutine) = caller();
    $subroutine = 'main' unless defined($subroutine);
    print STDERR "$subroutine: ", @_, "\n";
    print STDERR "from: $filename +$line\n";
    exit $exit_status;
}

sub message {
    print STDERR @_, "\n";
    return 1;
}
